//上传大文件切片
class SliceUploader {
	constructor(options) {
		this.url = options.url; // 上传API的URL
		this.progressType = options.progressType || false; // 返回的进度类型 true 长度 false 百分比
		this.filePath = (options.file ? options.file.path : '') || ''; // 文件的本地路径
		this.chunkSize = options.chunkSize || 1024 * 1024; // 切片大小，默认1MB
		this.onProgressUpdate = options.onProgressUpdate; // 进度更新回调
		this.onComplete = options.onComplete; // 上传完成回调
		this.onError = options.onError; // 错误回调
		this.headers = options.headers || {}; // 请求头
		this.formData = options.formData || {}; // 表单数据
		this.totalSize = (options.file ? options.file.size : 0) || 0; // 文件总大小
		this.chunkCount = this.totalSize ? Math.ceil(this.totalSize / this.chunkSize) : 0; // 切片总数
		this.currentChunk = 0; // 当前切片索引
		this.fileSystemManager = uni.getFileSystemManager(); // 文件系统管理器
		this.resultData = null; //上传完毕之后的数据
	}

	// 选择文件
	chooseFile() {
		return new Promise((resolve, reject) => {
			uni.chooseFile({
				count: 1,
				success: (res) => {
					this.filePath = res.tempFilePaths[0];
					this.totalSize = res.tempFiles[0].size;
					this.chunkCount = Math.ceil(this.totalSize / this.chunkSize);
					resolve();
				},
				fail: (err) => reject(err)
			});
		});
	}

	//创建切片文件
	fileSliceStart(filePath, start, end) {
		// #ifndef APP-PLUS
		const res = this.fileSystemManager.readFileSync(filePath, 'binary', start, end);
		// console.log("fileSlice", start, end);
		try {
			this.fileSystemManager.writeFileSync( //保存片文件
				this.filePath, //给文件一个路径		 
				res,
				'binary'
			)
			return true;
		} catch (e) {
			console.log("write error");
			console.error(e)
			return false;
		}
		// #endif	
		return true;
	}
	
	getFileInfo(){
		// #ifdef MP-WEIXIN
		return new Promise((resolve, reject) => {
		   wx.getFileSystemManager().getFileInfo({
		     filePath: this.filePath,
		     success: (res) => {
		       resolve(res);
		     },
		     fail: (err) => {
		       reject(err);
		     },
		   });
		 });
		// #endif
		// #ifndef MP-WEIXIN
		return uni.getFileInfo({
			filePath: this.filePath,
		})
		// #endif
	}

	// 开始上传
	async upload() {
		if (!this.filePath) {
			throw new Error('=====sliceUploader=====filePath is error');
		}

		if (!this.url) {
			throw new Error('=====sliceUploader=====url is error');
		}

		const res = await this.getFileInfo();
		const fileMd5 = res.digest
		// 删除生成的临时文件
		// #ifdef MP-WEIXIN
		let path = `${wx.env.USER_DATA_PATH}/`;
		const fs = uni.getFileSystemManager()
		fs.readdir({ // 获取文件列表
			dirPath: path, // 当时写入的文件夹
			success(res) {
				res.files.forEach((el) => { // 遍历文件列表里的数据
					// 删除存储的垃圾数据
					let dirs = `${path}${el}`;
					fs.unlink({
						filePath: dirs, // 这里注意。文件夹也要加上，如果直接文件名的话会无法找到这个文件
						success() {
							console.log('======remove file success=====', dirs);
						},
						fail(e) {
							console.log('readdir文件删除失败：', e)
						}
					});
				})
			}
		})
		// #endif


		let chunk_id = Number(Math.random().toString().substr(5, 10) + Date.now()).toString(36);
		let pos = this.filePath.lastIndexOf('/');
		let filename = this.filePath.substr(pos + 1);
		let filePath = this.filePath;

		while (this.currentChunk < this.chunkCount) {
			try {
				const start = this.currentChunk * this.chunkSize;
				const isLastChunk = this.currentChunk === this.chunkCount - 1;
				const end = isLastChunk ? this.totalSize : start + this.chunkSize;
				const chunkSize = end - start;

				// 更新formData中的切片信息
				let blob_num = this.currentChunk + 1;
				this.formData.chunk_id = chunk_id;
				this.formData.blob_num = blob_num;
				this.formData.total_blob_num = this.chunkCount;
				this.formData.file_name = filename;
				this.formData.md5 = fileMd5;
				// #ifdef MP-WEIXIN
				this.filePath = `${wx.env.USER_DATA_PATH}/${blob_num}_${filename}`;
				// #endif
				let result = this.fileSliceStart(filePath, start, chunkSize)
				if (!result) {
					throw new Error('写入文件失败！')
				}
				await this.uploadChunk().then(ret => {
					this.currentChunk++;
					if (ret.code == 200) {
						this.currentChunk += this.chunkCount
						this.resultData = ret.data;
					}
					// 如果有进度回调，执行它
					if (typeof this.onProgressUpdate === 'function') {
						let prog = this.progressType ? this.currentChunk : ((this.currentChunk / this
								.chunkCount) * 100)
							.toFixed(2);
						// let prog = this.progressType ? this.currentChunk : Math.ceil((this.currentChunk / this
						// 	.chunkCount) * 100);
						let progCount = this.progressType ? this.chunkCount : 100;
						this.onProgressUpdate(prog, progCount);
					}
				}).catch(err => {
					throw new Error(err)
				});
			} catch (err) {
				if (typeof this.onError === 'function') {
					this.onError(err);
				}
				break;
			}
		}

		if (this.currentChunk >= this.chunkCount) {
			if (typeof this.onComplete === 'function') {
				this.onComplete(this.resultData);
			}
		}
	}

	// 上传单个切片
	uploadChunk() {
		return new Promise((resolve, reject) => {
			// console.log('===this.formData===', this.filePath, this.formData);
			// return false;
			uni.uploadFile({
				url: this.url,
				filePath: this.filePath,
				name: 'file',
				formData: this.formData,
				header: this.headers,
				success: (res) => {
					let data = res.data
					if (typeof data == "string") {
						data = JSON.parse(data)
					}
					resolve(data);
				},
				fail: (err) => {
					reject(err);
				}
			});
		});
	}
}
//调用示例
// const uploader = new SliceUploader({
// 	url: uploadUrl,
// 	file: this.file,
// 	onProgressUpdate: (currentChunk, totalChunks) => {
// 		this.$emit('prog', currentChunk)
// 	},
// 	onComplete: (resultData) => {
// 		this.$emit('success', resultData.downTaskId)
// 	},
// 	onError: (err) => {
// 		let msg = err.msg || ''
// 		this.$toast('上传失败'+msg);
// 	}
// }).upload();

export default SliceUploader;